package com.sudichina.sudichina.NET;


import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;

import com.lzy.okgo.OkGo;
import com.lzy.okgo.callback.StringCallback;
import com.sudichina.sudichina.MyApp;
import com.sudichina.sudichina.utils.L;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;


/**
 * 请求数据
 *
 * @author yangweiqiao
 */
@SuppressWarnings("unused")
public class NetUtils {
    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    private static final MediaType FILE = MediaType.parse("application/octet-stream");


    private static final MediaType IMG = MediaType.parse("image/jpeg; charset=utf-8");
    //    private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
    //multipart/form-data
    //测试地址
   private static final String HOSTURL = "http://192.168.0.201:8888/";
    //正式地址
 //private static final String HOSTURL = "http://210.12.63.49:8888/";
    private static Type type;
    /***
     * 创建handler 用于将数据发往主线程  因为okhttp的请求是在子线程  我们需要将结果发往主线程  子线程是不能更新ui的
     */
    private static Handler mHandler = new Handler(Looper.getMainLooper());

    /**
     * 请求数据示例:
     * http://192.168.1.100:8080/yangweiqiao/list/news/page0.xml
     *
     * @param catalog  第一个参数 分类 代表当前请求数据的接口
     * @param map      传进来post请求的参数 如果是get请求 直接传入null 集合会在下面的方法里面变量封装为请求对象
     * @param listener 第三个参数  网络请求的接口回调 会返回请求的数据 这里本次修改为返回一个对象
     *                 这个方法请求到数据之后,解析数据 调用方法解析数据为对象 根据第五个参数  传进来的是一个Class对象
     * @param types    根据这个来解析出一个object对象    如果不需要解析  直接传入的null
     * @param isCache  是否需要缓存数据 如果需要做缓存 这个参数传进来true  不需要缓存  传入是false
     */

    public static void requestData(final String catalog, final HashMap<String, Object> map, final onRequestDataFinish listener, Type types, Boolean isCache) {
        type = types;
        /**
         * 判断是否做缓存
         * */
        if (isCache) {
            /** 做缓存  */
         /*
         * 创建url缓存地址
         */
            final String cacheFileName = creatCacheFileName(catalog, map);
             /*
         * 判断是否有缓存文件
         */

            File cacheFile = getCacheFile(cacheFileName);

           /*
           判断缓存是否有效
            */

            boolean isused = isUsed(cacheFile);

            if (isused) {//true为有效
                /**
                 * 从缓存文件中读取数据
                 */

                getDataFromCache(catalog, cacheFile, listener);
            } else {

                /**
                 * 缓存文件失效了 过了有效期
                 */
                new Thread() {
                    public void run() {
                        //访问网络代码 (核心方法)
                        getDataFromNet(cacheFileName, catalog, map, listener);  //第一个参数是缓存的文件名字 访问后还是要继续缓存的
                    }
                }.start();

            }

        } else {
            /** 数据不需要缓存  */
            /**
             * 从网络中请求数据 缓存数据
             */

            new Thread() {
                public void run() {
                    //访问网络代码
                    getDataFromNet(null, catalog, map, listener); //第一个参数null 访问后不需要做缓存
                }
            }.start();


        }


    }

    /**
     * 创建缓存文件的名称
     *
     * @param catalog 类型
     * @param values  参数
     * @return 拼接完成的文件名称
     */
    private static String creatCacheFileName(String catalog, HashMap values) {

        /**根据传入进来的参数创建缓存文件名字*/
        if (values == null) {

            return catalog;
        } else {
            return catalog + values.toString();
        }

    }

    /**
     * 获取缓存文件
     *
     * @param cacheFileName 根据文件名字去获取文件
     * @return file
     */
    private static File getCacheFile(String cacheFileName) {

        try {
            // 进行编码
            cacheFileName = URLEncoder.encode(cacheFileName, "utf-8");
//返回缓存文件
            return new File(MyApp.getContext().getCacheDir(), cacheFileName);


        } catch (Exception e) {

            e.printStackTrace();
        }

        return null;
    }

    /**
     * 判断缓存文件是否有效
     *
     * @param cacheFile 缓存的文件
     * @return boolean
     */
    private static boolean isUsed(File cacheFile) {

        //判断缓存文件是否有效,

        /**
         1.首先判断文件是否为null 或者是不存在的
         */
        if (cacheFile == null || !cacheFile.exists()) {
            //条件满足一个 就返回false

            return false; //文件不存在
        }
        /**
         2. 判断文件存在的情况
         */
        //定义文件的有效
        /*
         TODO  这里定义的是缓存文件的有效时间
          */
        long isUsedTime = MyApp.getCacheFileExpiryDate();
        /** 获取文件最后的修改时间 */
        long modified = cacheFile.lastModified();
        /** 获取系统的当前的时间 */
        long millis = System.currentTimeMillis();
        /** 计算系统当前的时间和文件最后修改时间的差值 */
        long times = millis - modified;
        /** 如果有效时间 大于 差值 返回true 证明文件有效 */
        return isUsedTime > times;


    }

    /**
     * 从缓存文件中获取数据
     *
     * @param cacheFile 缓存文件
     * @param listener  获取数据后实现接口然后可以获取数据
     */
    private static void getDataFromCache(final String catalog, final File cacheFile, final onRequestDataFinish listener) {


        //读取缓存文件
        new AsyncTask<Void, Void, String>() {
            /**在子线程操作的方法**/
            @Override
            protected String doInBackground(Void... params) {
                BufferedReader reader;
//读取文件的方法  不解释
                try {
                    reader = new BufferedReader(new FileReader(cacheFile));

                    String line;
                    StringBuilder sb = new StringBuilder();
                    try {
                        while ((line = reader.readLine()) != null) {

                            sb.append(line).append("\n");
                        }
                        String json = sb.toString();

                        reader.close();
                        //返回json
                        return json;
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }

                return null;
            }

            /**
             * 执行的结果  通过这个方法获取上面的方法执行的结果
             * @param result
             */
            @Override
            protected void onPostExecute(String result) {
                super.onPostExecute(result);
                //这里的参数是上面的那个方法返回的数据
//这里我们直接把json解析出来  返回为一个bean对象
                if (type == null) {
                    //不需要解析  直接传递json回去
                    listener.requestdataFinish(catalog, result);
                } else {
                    Object bean = JsonUtil.parseJsonToBean(result, type);
                    //解析好的结果 我们需要判断
                    if (bean != null) {
                        //如果传递的class文件是错误的或者json是错误的 不能解析
                        //把数据传递给调用者
                        listener.requestdataFinish(catalog, bean);
                    } else {
                        //传递json回去
                        listener.requestdataFinish(catalog, result);
                    }
                }
            }

        }.execute();


    }

    /**
     * 从网络获取数据
     *
     * @param cacheFileName 缓存文件名称
     * @param catalog       地址接口
     * @param map           参数
     * @param listener      监听接口
     */
    private static void getDataFromNet(final String cacheFileName, final String catalog, final HashMap map, final onRequestDataFinish listener) {

//这里的方法没有添加
        OkHttpClient okHttpClient = new OkHttpClient();


        Request request = null;

        /**
         * 判斷請求的方式
         */
        if (map == null) {
            //get请求 不需要添加请求体
            request = new Request.Builder()
                    .url(HOSTURL + catalog)
                    .build();

        } else {
//post请求


            String json = JsonUtil.parseMapToJson(map);
            System.out.println("请求的参数是:"+json);
            RequestBody requestBody = RequestBody.create(JSON, json);

//            /**以自己的方式创建请求体**/
//            FormEncodingBuilder builder = new FormEncodingBuilder();
//            Set<String> set = map.keySet();
///**遍历集合 添加请求体 **/
//            for (String key : set) {
//
//                builder.add(key, String.valueOf(map.get(key)));
//                L.e("测试服务器的数据:" + key + "values" + map.get(key));
//            }
//

//
//            //创建请求体
//            RequestBody requestBody = builder.build();

            request = new Request.Builder()
                    .url(HOSTURL + catalog) //catalog 参数是传入的网络请求接口
                    .post(requestBody)
//                .addHeader("token", "helloworldhelloworldhelloworld") 这里不需要添加请求头
                    .build();

        }
/**
 * 异步请求  数据会在子线程
 */
        okHttpClient.newCall(request)
                .enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, final IOException e) {
                        /**
                         * 网络请求失败  将数据发往主线程
                         */

                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                listener.requestdataFailed(e);
                            }
                        });


                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        final String string = response.body().string();
                        /**
                         * 解析数据
                         */

                        //将数据发往主线程
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                L.e("json", string);

                                if (type == null) {
                                    //直接返回json

                                    listener.requestdataFinish(catalog, string);
                                } else {
                                    /**
                                     *发送之前判断数据 如果json格式错误 或者是class传递的错误 解析的bean是null
                                     */
                                    Object bean = JsonUtil.parseJsonToBean(string, type);
                                    if (bean == null) {
                                        listener.requestdataFinish(catalog, string);

                                    } else {
                                        listener.requestdataFinish(catalog, bean);
                                    }
                                }


                            }
                        });
                        /**
                         * 请求完数据之后 做数据的缓存判断
                         */

                        if (null != cacheFileName) { //判断需要缓存的文件名字
                            /**需要缓存 */
                            cacheData(string, catalog);
                        }

                    }
                });

    }


    /**
     * 缓存数据 参数是 xml字符串
     *
     * @param result   json数据缓存
     * @param fileName 文件名称
     */
    private static void cacheData(String result, String fileName) {
        if (TextUtils.isEmpty(result)) {
            //如果 数据为空,返回,不再继续缓存
            return;

        }

        //根据文件名获取
        File cacheFile = getCacheFile(fileName);
        BufferedWriter writer = null;
        try {

            //写入缓存
            writer = new BufferedWriter(new FileWriter(cacheFile));
            writer.write(result);
            writer.flush(); //刷新进去数据

        } catch (IOException e) {
            e.printStackTrace();
        } finally {


        }


    }

    /**
     * 表单文件上传
     *
     * @param url      地址
     * @param data     其他的参数
     * @param file     文件map
     * @param types    解析的类型 不需要直接传null
     * @param listener 回调
     */

    public static void formPost(final String url, Map<String, Object> data, Map<String, String> file, Type types, final onRequestDataFinish listener) {
        File file1 = null;


        if (file != null) {
            for (Map.Entry<String, String> entry : file.entrySet()) {
                String uri = entry.getValue();
                int lastIndex = uri.lastIndexOf("/");

                file1 = new File(entry.getValue());

            }
        }

        OkGo.post(HOSTURL + url)
                .isMultipart(true)       // 强制使用 multipart/form-data 表单上传（只是演示，不需要的话不要设置。默认就是false）
                .params("fieldName", file1.getName())
                .params("accountId", String.valueOf(data.get("accountId")))
                .params("realName", String.valueOf(data.get("realName")))
                .params("drivingLicense", String.valueOf(data.get("drivingLicense")))
                .params("fileName", file1.getName())
                .params("drivingLicensePath", file1)   // 可以添加文件上传
                // 这里支持一个key传多个文件
                .execute(new StringCallback() {
                    @Override
                    public void onSuccess(final String s, Call call, Response response) {
                        //上传成功

                        final String string;


                        //将数据发往主线程
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                L.e("json", s);

                                if (type == null) {
                                    //直接返回json

                                    listener.requestdataFinish(url, s);
                                } else {
                                    /**
                                     *发送之前判断数据 如果json格式错误 或者是class传递的错误 解析的bean是null
                                     */
                                    Object bean = JsonUtil.parseJsonToBean(s, type);
                                    if (bean == null) {
                                        listener.requestdataFinish(url, s);

                                    } else {
                                        listener.requestdataFinish(url, bean);
                                    }
                                }


                            }
                        });


                    }


                    @Override
                    public void upProgress(long currentSize, long totalSize, float progress, long networkSpeed) {
                        //这里回调上传进度(该回调在主线程,可以直接更新ui)

                    }
                });

    }

    public static void formPost2(final String url, Map<String, Object> data, Map<String, String> file, Type types, final onRequestDataFinish listener) {
        File file1 = null;
        ArrayList<File> files = new ArrayList<>();

        if (file != null) {
            for (Map.Entry<String, String> entry : file.entrySet()) {
                String uri = entry.getValue();
                int lastIndex = uri.lastIndexOf("/");

                file1 = new File(entry.getValue());
                System.out.println(file1);
                files.add(file1);
            }
        }
/**
 *   map.put("carFirstLetter", tvvehiclefirstletter);
 map.put("cardNumber", etnumberplate);
 map.put("carDicId", 46);
 map.put("engineNum", etenginenumber);
 HashMap<String, String> hashMap = new HashMap<>();

 hashMap.put("driveLicensePath", driveLicensePath);
 hashMap.put("driveLicensePath2", driveLicensePath);
 */
        OkGo.post(HOSTURL + url)
                .isMultipart(true)       // 强制使用 multipart/form-data 表单上传（只是演示，不需要的话不要设置。默认就是false）
                .params("fieldName", files.get(0).getName())

                .params("accountId", String.valueOf(data.get("accountId")))

                .params("carFirstLetter", String.valueOf(data.get("carFirstLetter")))
                .params("carDicId", String.valueOf(data.get("carDicId")))
                .params("cardNumber", String.valueOf(data.get("cardNumber")))

                .params("fileName", file1.getName())
/**
 *   map.put("carWeight", etvehiclevolume);
 map.put("carCube", etvehiclearea);
 */
                .params("carWeight", String.valueOf(data.get("carWeight")))
                .params("carCube", String.valueOf(data.get("carCube")))

                .params("driveLicensePath", files.get(0))   // 可以添加文件上传
                .params("driveLicensePath2", files.get(1))   // 可以添加文件上传
                // 这里支持一个key传多个文件
                .execute(new StringCallback() {
                    @Override
                    public void onSuccess(final String s, Call call, Response response) {
                        //上传成功

                        final String string;

                        System.out.println("上传成功...ok ");
                        //将数据发往主线程
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                L.e("json", s);

                                if (type == null) {
                                    //直接返回json

                                    listener.requestdataFinish(url, s);
                                } else {
                                    /**
                                     *发送之前判断数据 如果json格式错误 或者是class传递的错误 解析的bean是null
                                     */
                                    Object bean = JsonUtil.parseJsonToBean(s, type);
                                    if (bean == null) {
                                        listener.requestdataFinish(url, s);

                                    } else {
                                        listener.requestdataFinish(url, bean);
                                    }
                                }


                            }
                        });


                    }


                    @Override
                    public void upProgress(long currentSize, long totalSize, float progress, long networkSpeed) {
                        //这里回调上传进度(该回调在主线程,可以直接更新ui)

                    }
                });

    }

    public static void requestDataformentity(final String url, Object bean, final onRequestDataFinish listener, final Type types) {
        type = types;
        //这里的方法没有添加
        OkHttpClient okHttpClient = new OkHttpClient();


        Request request = null;


        {
//post请求


            String json = JsonUtil.parseBeanToJson(bean);


            RequestBody requestBody = RequestBody.create(JSON, json);

            System.out.println("访问的json:" + json);
            System.out.println("访问的地址是:" + HOSTURL + url);


            request = new Request.Builder()
                    .url(HOSTURL + url) //catalog 参数是传入的网络请求接口
                    .post(requestBody)
//                .addHeader("token", "helloworldhelloworldhelloworld") 这里不需要添加请求头
                    .build();

        }
/**
 * 异步请求  数据会在子线程
 */
        okHttpClient.newCall(request)
                .enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, final IOException e) {
                        /**
                         * 网络请求失败  将数据发往主线程
                         */

                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                listener.requestdataFailed(e);
                            }
                        });


                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        final String string = response.body().string();
                        /**
                         * 解析数据
                         */

                        //将数据发往主线程
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                L.e("json", string);

                                if (type == null) {
                                    //直接返回json

                                    listener.requestdataFinish(url, string);
                                } else {
                                    /**
                                     *发送之前判断数据 如果json格式错误 或者是class传递的错误 解析的bean是null
                                     */
                                    Object bean = JsonUtil.parseJsonToBean(string, type);
                                    if (bean == null) {
                                        listener.requestdataFinish(url, string);

                                    } else {
                                        listener.requestdataFinish(url, bean);
                                    }
                                }


                            }
                        });


                    }
                });


    }
}
